#include <cstddef>
#include <cstdint>

/************************************************************************************************/
/* 										内存管理												*/
/* malloc()/free(), new/delete 是动态内存分配, 又成为堆分配。应尽量减少使用						*/
/*==============================================================================================*/ 
/* 1. 堆栈分配器																				*/
/* 分配一大块连续内存																			*/
/* 另外安排指针指向堆栈顶端, 指针以下的内存是已经分配的,指针以上是未分配						*/
/* 对于每个分配请求,即把指针向上移动															*/
/* 注意:不能以任意次序释放内存，必须按照分配相反的顺序释放。可以不允许释放单个内存块, 只允许回滚指针
/*----------------------------------------------------------------------------------------------*/ 
/* 2. 双端堆栈分配器																			*/
/* 比如底堆栈用来分配给场景，顶堆栈用来分配临时内存块											*/
/*----------------------------------------------------------------------------------------------*/ 
/* 3. 池分配器																					*/
/* 预分配一大块内存，大小是元素的整数倍。比如4*4矩阵的池分配器，预先分配64B整数倍的内存			*/
/* 池内的每个元素添加到一个存放自由元素的链表中													*/
/* 分配即从自由链表中取出一个元素，释放即将元素插回到自由链表中									*/
/*----------------------------------------------------------------------------------------------*/ 
/* 3. 池分配器																					*/
/************************************************************************************************/

namespace feifei
{
    struct BlockHeader
    {
        // union-ed with data
        BlockHeader* pNext;
    };

    struct PageHeader 
    {
        PageHeader* pNext;
        BlockHeader* Blocks() 
        {
            return reinterpret_cast<BlockHeader*>(this + 1);
        }
    };

    class Allocator 
    {
    public:
        // debug patterns
        static const uint8_t PATTERN_ALIGN = 0xFC;
        static const uint8_t PATTERN_ALLOC = 0xFD;
        static const uint8_t PATTERN_FREE = 0xFE;

        Allocator();
        Allocator(size_t data_size, size_t page_size, size_t alignment);
        ~Allocator();

        // resets the allocator to a new configuration
        void Reset(size_t data_size, size_t page_size, size_t alignment);

        // alloc and free blocks
        void* Allocate();
        void  Free(void* p);
        void  FreeAll();

    private:
        // gets the next block
        BlockHeader* NextBlock(BlockHeader* pBlock);

        // the page list
        PageHeader* m_pPageList;

        // the free block list
        BlockHeader* m_pFreeList;

        size_t      m_szDataSize;
        size_t      m_szPageSize;
        size_t      m_szAlignmentSize;
        size_t      m_szBlockSize;
        uint32_t    m_nBlocksPerPage;

        // statistics
        uint32_t    m_nPages;
        uint32_t    m_nBlocks;
        uint32_t    m_nFreeBlocks;

        // disable copy & assignment
        Allocator(const Allocator& clone);
        Allocator& operator=(const Allocator& rhs);
    };
}
